package io.kiki.sba.registry.common.model.store;

import io.kiki.sba.registry.concurrent.ThreadLocalStringBuilder;
import lombok.Getter;
import lombok.Setter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.Serializable;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.util.Objects;

@Setter
@Getter
public final class Url implements Serializable {
    /**
     * symbol :
     */
    public static final char COLON = ':';
    public static final byte HESSIAN_2 = 1;
    public static final byte PROTOBUF = 11;
    private static final Logger logger = LoggerFactory.getLogger(Url.class);
    private ProtocolType protocol;

    @Getter
    private String ip;

    @Getter
    private int port;

    @Getter
    private Byte serializerIndex;

    public Url() {
    }


    public Url(ProtocolType protocol, String ip, int port, Byte serializerIndex) {
        this.protocol = protocol;
        this.ip = StringInterner.intern(getIPAddressFromDomain(ip));
        this.port = port;
        this.serializerIndex = serializerIndex;
    }


    public Url(String ip, int port) {
        this(null, ip, port, HESSIAN_2);
    }


    public Url(InetSocketAddress address) {
        this(null, address.getAddress().getHostAddress(), address.getPort(), HESSIAN_2);
    }

    public Url(InetSocketAddress address, Byte serializerIndex) {
        this(null, address.getAddress().getHostAddress(), address.getPort(), serializerIndex);
    }


    public Url(String ip) {
        this(ip, 0);
    }

    public static Url internURL(Url url) {
        if (url == null) {
            return null;
        }
        url.setIp(url.getIp());
        return url;
    }


    /**
     * TODO Other protocol
     */
    public static Url valueOf(String url) {

        if (url == null || (url = url.trim()).length() == 0) {
            throw new IllegalArgumentException("url == null");
        }
        String ipAddress = "";
        int port = 0;
        ProtocolType protocol = null;

        int i = url.indexOf(":");
        if (i >= 0 && i < url.length() - 1) {
            port = Integer.parseInt(url.substring(i + 1));
            url = url.substring(0, i);
        }
        if (url.length() > 0) {
            ipAddress = url;
        }

        return new Url(protocol, ipAddress, port, HESSIAN_2);
    }


    public void setIp(String ip) {
        this.ip = StringInterner.intern(ip);
    }


    public String buildAddressString() {
        StringBuilder builder = ThreadLocalStringBuilder.get().append(ip).append(COLON).append(port);
        return builder.toString();
    }


    private String getIPAddressFromDomain(String domain) {
        try {
            InetAddress inetAddress = InetAddress.getByName(domain);
            return inetAddress.getHostAddress();
        } catch (UnknownHostException e) {
            logger.error("Can not resolve " + domain + " really ip.");
        }
        return domain;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o)
            return true;
        if (o == null || getClass() != o.getClass())
            return false;
        Url url = (Url) o;
        return port == url.port && protocol == url.protocol && Objects.equals(ip, url.ip);
    }

    @Override
    public int hashCode() {
        return Objects.hash(protocol, ip, port);
    }


    public enum ProtocolType {
        tr, netty, http
    }
}
